```html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>AOP横切技术解析 | 技术小馆</title>
    <link href="https://cdn.staticfile.org/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
    <link href="https://cdn.staticfile.org/tailwindcss/2.2.19/tailwind.min.css" rel="stylesheet">
    <link href="https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@400;500;600;700&family=Noto+Sans+SC:wght@300;400;500;700&display=swap" rel="stylesheet">
    <style>
        body {
            font-family: 'Noto Sans SC', Tahoma, Arial, Roboto, "Droid Sans", "Helvetica Neue", "Droid Sans Fallback", "Heiti SC", "Hiragino Sans GB", Simsun, sans-serif;
            background-color: #f8fafc;
            color: #1e293b;
        }
        h1, h2, h3, h4, h5 {
            font-family: 'Noto Serif SC', serif;
        }
        .hero-bg {
            background: linear-gradient(135deg, #4f46e5 0%, #7c3aed 100%);
        }
        .code-block {
            background-color: #1e293b;
            border-radius: 8px;
            box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
        }
        .code-block pre {
            margin: 0;
            padding: 1.5rem;
            overflow-x: auto;
        }
        .code-block code {
            font-family: 'Courier New', Courier, monospace;
            color: #e2e8f0;
            font-size: 0.9rem;
            line-height: 1.5;
        }
        .feature-card {
            transition: all 0.3s ease;
        }
        .feature-card:hover {
            transform: translateY(-5px);
            box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
        }
        .mermaid {
            background-color: white;
            border-radius: 8px;
            padding: 2rem;
            box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
        }
        .hover-underline-animation {
            display: inline-block;
            position: relative;
        }
        .hover-underline-animation::after {
            content: '';
            position: absolute;
            width: 100%;
            transform: scaleX(0);
            height: 2px;
            bottom: -2px;
            left: 0;
            background-color: #4f46e5;
            transform-origin: bottom right;
            transition: transform 0.25s ease-out;
        }
        .hover-underline-animation:hover::after {
            transform: scaleX(1);
            transform-origin: bottom left;
        }
    </style>
</head>
<body>
    <!-- Hero Section -->
    <section class="hero-bg text-white py-20 px-4 md:px-0">
        <div class="container mx-auto max-w-5xl">
            <div class="flex flex-col items-center text-center">
                <h1 class="text-4xl md:text-5xl font-bold mb-6">AOP横切技术解析</h1>
                <p class="text-xl md:text-2xl max-w-3xl mb-8 opacity-90">
                    掌握Spring AOP与自定义注解的强大组合，实现优雅的横切逻辑处理
                </p>
                <div class="flex space-x-4">
                    <a href="#basic-aop" class="px-6 py-3 bg-white text-indigo-600 font-medium rounded-lg shadow hover:bg-gray-100 transition duration-300">
                        <i class="fas fa-code mr-2"></i>基础AOP
                    </a>
                    <a href="#custom-annotation" class="px-6 py-3 bg-transparent border-2 border-white text-white font-medium rounded-lg hover:bg-white hover:text-indigo-600 transition duration-300">
                        <i class="fas fa-tags mr-2"></i>自定义注解
                    </a>
                </div>
            </div>
        </div>
    </section>

    <!-- Main Content -->
    <main class="container mx-auto max-w-5xl py-12 px-4 md:px-0">
        <!-- Intro Section -->
        <section class="mb-16">
            <div class="flex items-center mb-6">
                <div class="h-1 bg-indigo-500 w-12 rounded-full"></div>
                <span class="ml-4 text-indigo-600 font-medium">技术解析</span>
            </div>
            <h2 class="text-3xl font-bold mb-6">AOP横切技术概述</h2>
            <div class="prose max-w-none text-gray-700">
                <p class="text-lg leading-relaxed">
                    在Spring框架中，AOP（Aspect-Oriented Programming）是一种强大的编程范式，它允许开发者通过切面（Aspect）对Controller的参数和方法进行横切（Cross-cutting）处理。横切关注的是那些跨越多个对象的通用功能逻辑，如日志记录、权限控制、参数校验等。
                </p>
                <p class="mt-4 text-lg leading-relaxed">
                    使用AOP可以有效地解耦业务逻辑和横切关注点，使代码更加模块化、可维护。本文将深入探讨两种实现方式：基础AOP和基于自定义注解的AOP，帮助开发者选择最适合自己项目的方案。
                </p>
            </div>
        </section>

        <!-- Basic AOP Section -->
        <section id="basic-aop" class="mb-16">
            <div class="flex items-center mb-6">
                <div class="h-1 bg-indigo-500 w-12 rounded-full"></div>
                <span class="ml-4 text-indigo-600 font-medium">基础实现</span>
            </div>
            <h2 class="text-3xl font-bold mb-6">通过AOP注解实现横切</h2>
            
            <div class="prose max-w-none text-gray-700 mb-8">
                <p>
                    基础AOP实现方式通过定义切面类和通知（Advice）来拦截Controller方法，通常使用<code>@Before</code>或<code>@Around</code>通知来实现参数处理逻辑。这种方式简单直接，适合处理固定场景下的横切需求。
                </p>
            </div>
            
            <div class="grid md:grid-cols-2 gap-8 mb-12">
                <div class="code-block">
                    <div class="flex items-center bg-gray-800 px-4 py-2 rounded-t-lg">
                        <div class="flex space-x-2">
                            <div class="w-3 h-3 rounded-full bg-red-500"></div>
                            <div class="w-3 h-3 rounded-full bg-yellow-500"></div>
                            <div class="w-3 h-3 rounded-full bg-green-500"></div>
                        </div>
                        <span class="text-gray-400 ml-3 text-sm">ParameterAspect.java</span>
                    </div>
                    <pre><code>@Aspect
@Component
public class ParameterAspect {

    @Before("execution(* com.ts.demo.controller.MyController.*(..))")
    public void beforeControllerMethod(JoinPoint joinPoint) {
        Object[] args = joinPoint.getArgs();
        for (Object arg : args) {
            // 对参数进行处理
            if (arg instanceof String) {
                String newArg = ((String) arg).toUpperCase();
                System.out.println("Original arg: " + arg 
                    + ", Processed arg: " + newArg);
            }
        }
    }
}</code></pre>
                </div>
                
                <div class="code-block">
                    <div class="flex items-center bg-gray-800 px-4 py-2 rounded-t-lg">
                        <div class="flex space-x-2">
                            <div class="w-3 h-3 rounded-full bg-red-500"></div>
                            <div class="w-3 h-3 rounded-full bg-yellow-500"></div>
                            <div class="w-3 h-3 rounded-full bg-green-500"></div>
                        </div>
                        <span class="text-gray-400 ml-3 text-sm">MyController.java</span>
                    </div>
                    <pre><code>@RestController
public class MyController {

    @GetMapping("/hello")
    public String sayHello(@RequestParam("name") String name) {
        return "Hello, " + name + "!";
    }
}</code></pre>
                </div>
            </div>
            
            <div class="bg-blue-50 border-l-4 border-blue-500 p-6 rounded-r-lg mb-8">
                <div class="flex items-start">
                    <div class="flex-shrink-0 text-blue-500 mr-4">
                        <i class="fas fa-info-circle text-xl"></i>
                    </div>
                    <div>
                        <h4 class="text-lg font-semibold text-blue-800 mb-2">关键点解析</h4>
                        <ul class="text-blue-700 space-y-2">
                            <li><span class="font-medium">@Aspect</span> 注解标识该类为切面类</li>
                            <li><span class="font-medium">@Before</span> 通知在目标方法执行前触发</li>
                            <li>切入点表达式 <span class="font-mono">execution(* com.ts.demo.controller.MyController.*(..))</span> 匹配目标方法</li>
                            <li><span class="font-medium">JoinPoint</span> 提供方法执行上下文信息</li>
                        </ul>
                    </div>
                </div>
            </div>
            
            <div class="prose max-w-none text-gray-700">
                <p>
                    当请求<code>/hello?name=John</code>时，AOP切面会拦截方法调用，将<code>name</code>参数转换为大写并输出日志。这种基础实现方式虽然简单，但适用于大多数常见的横切场景，如参数校验、日志记录等。
                </p>
            </div>
        </section>

        <!-- Custom Annotation Section -->
        <section id="custom-annotation" class="mb-16">
            <div class="flex items-center mb-6">
                <div class="h-1 bg-indigo-500 w-12 rounded-full"></div>
                <span class="ml-4 text-indigo-600 font-medium">进阶应用</span>
            </div>
            <h2 class="text-3xl font-bold mb-6">AOP+自定义注解实现横切</h2>
            
            <div class="prose max-w-none text-gray-700 mb-8">
                <p>
                    结合自定义注解的AOP实现提供了更灵活的横切方式，通过注解精准标记需要处理的参数或方法，使代码意图更清晰，可复用性更强。
                </p>
            </div>
            
            <div class="grid md:grid-cols-3 gap-8 mb-12">
                <div class="code-block">
                    <div class="flex items-center bg-gray-800 px-4 py-2 rounded-t-lg">
                        <div class="flex space-x-2">
                            <div class="w-3 h-3 rounded-full bg-red-500"></div>
                            <div class="w-3 h-3 rounded-full bg-yellow-500"></div>
                            <div class="w-3 h-3 rounded-full bg-green-500"></div>
                        </div>
                        <span class="text-gray-400 ml-3 text-sm">UpperCase.java</span>
                    </div>
                    <pre><code>@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface UpperCase {
}</code></pre>
                </div>
                
                <div class="code-block">
                    <div class="flex items-center bg-gray-800 px-4 py-2 rounded-t-lg">
                        <div class="flex space-x-2">
                            <div class="w-3 h-3 rounded-full bg-red-500"></div>
                            <div class="w-3 h-3 rounded-full bg-yellow-500"></div>
                            <div class="w-3 h-3 rounded-full bg-green-500"></div>
                        </div>
                        <span class="text-gray-400 ml-3 text-sm">MyController.java</span>
                    </div>
                    <pre><code>@RestController
public class MyController {

    @GetMapping("/hello")
    public String sayHello(
        @UpperCase @RequestParam("name") String name) {
        return "Hello, " + name + "!";
    }
}</code></pre>
                </div>
                
                <div class="code-block">
                    <div class="flex items-center bg-gray-800 px-4 py-2 rounded-t-lg">
                        <div class="flex space-x-2">
                            <div class="w-3 h-3 rounded-full bg-red-500"></div>
                            <div class="w-3 h-3 rounded-full bg-yellow-500"></div>
                            <div class="w-3 h-3 rounded-full bg-green-500"></div>
                        </div>
                        <span class="text-gray-400 ml-3 text-sm">ParameterAspect.java</span>
                    </div>
                    <pre><code>@Aspect
@Component
public class ParameterAspect {

    @Around("@annotation(upperCase)")
    public Object aroundUpperCaseParam(
        ProceedingJoinPoint joinPoint, 
        UpperCase upperCase) throws Throwable {
        
        Object[] args = joinPoint.getArgs();
        for (int i = 0; i < args.length; i++) {
            if (args[i] instanceof String && 
                joinPoint.getArgs()[i].getClass()
                    .isAnnotationPresent(UpperCase.class)) {
                args[i] = ((String) args[i]).toUpperCase();
            }
        }
        return joinPoint.proceed(args);
    }
}</code></pre>
                </div>
            </div>
            
            <div class="bg-indigo-50 border-l-4 border-indigo-500 p-6 rounded-r-lg mb-8">
                <div class="flex items-start">
                    <div class="flex-shrink-0 text-indigo-500 mr-4">
                        <i class="fas fa-star text-xl"></i>
                    </div>
                    <div>
                        <h4 class="text-lg font-semibold text-indigo-800 mb-2">方案优势</h4>
                        <ul class="text-indigo-700 space-y-2">
                            <li><span class="font-medium">精准控制</span>：只处理标记了特定注解的参数</li>
                            <li><span class="font-medium">代码清晰</span>：通过注解明确表达意图</li>
                            <li><span class="font-medium">可扩展性</span>：易于添加新的处理逻辑</li>
                            <li><span class="font-medium">复用性强</span>：同一套切面可用于多个Controller</li>
                        </ul>
                    </div>
                </div>
            </div>
        </section>

        <!-- Comparison Section -->
        <section class="mb-16">
            <div class="flex items-center mb-6">
                <div class="h-1 bg-indigo-500 w-12 rounded-full"></div>
                <span class="ml-4 text-indigo-600 font-medium">方案对比</span>
            </div>
            <h2 class="text-3xl font-bold mb-6">两种实现方式对比</h2>
            
            <div class="grid md:grid-cols-2 gap-8 mb-8">
                <div class="feature-card bg-white p-6 rounded-xl shadow-md border border-gray-100">
                    <div class="text-indigo-500 mb-4">
                        <i class="fas fa-cube text-3xl"></i>
                    </div>
                    <h3 class="text-xl font-bold mb-3">基础AOP实现</h3>
                    <div class="prose text-gray-700 mb-4">
                        <ul>
                            <li>适用于固定模式的处理逻辑</li>
                            <li>实现简单直接</li>
                            <li>可能影响不相关的参数</li>
                            <li>修改范围需要调整切入点表达式</li>
                        </ul>
                    </div>
                    <div class="px-4 py-2 bg-indigo-100 text-indigo-800 rounded-lg inline-block text-sm font-medium">
                        适合简单场景
                    </div>
                </div>
                
                <div class="feature-card bg-white p-6 rounded-xl shadow-md border border-gray-100">
                    <div class="text-purple-500 mb-4">
                        <i class="fas fa-puzzle-piece text-3xl"></i>
                    </div>
                    <h3 class="text-xl font-bold mb-3">自定义注解+AOP</h3>
                    <div class="prose text-gray-700 mb-4">
                        <ul>
                            <li>精准控制处理目标</li>
                            <li>代码意图更加明确</li>
                            <li>易于扩展和维护</li>
                            <li>可实现多种处理逻辑组合</li>
                        </ul>
                    </div>
                    <div class="px-4 py-2 bg-purple-100 text-purple-800 rounded-lg inline-block text-sm font-medium">
                        推荐复杂场景
                    </div>
                </div>
            </div>
            
            <div class="prose max-w-none text-gray-700">
                <p>
                    根据项目复杂度和需求选择合适的实现方式。对于简单、固定的横切逻辑，基础AOP实现足够使用；而对于需要精准控制、多变的处理场景，自定义注解结合AOP的方式更为合适。
                </p>
            </div>
        </section>

        <!-- Visualization Section -->
        <section class="mb-16">
            <div class="flex items-center mb-6">
                <div class="h-1 bg-indigo-500 w-12 rounded-full"></div>
                <span class="ml-4 text-indigo-600 font-medium">技术图解</span>
            </div>
            <h2 class="text-3xl font-bold mb-6">AOP横切处理流程</h2>
            
            <div class="mermaid mb-8">
                graph TD
                    A[客户端请求] --> B[DispatcherServlet]
                    B --> C[Controller方法]
                    C -->|标记@UpperCase| D[AOP切面处理]
                    D --> E[参数转换处理]
                    E --> C
                    C --> F[返回响应]
            </div>
            
            <div class="prose max-w-none text-gray-700">
                <p>
                    上图展示了AOP横切处理的基本流程：当客户端发起请求后，DispatcherServlet会将请求路由到对应的Controller方法。如果方法或参数被特定注解标记，AOP切面会拦截调用，执行预先定义的横切逻辑（如参数转换），然后再继续执行原始方法逻辑，最后返回响应给客户端。
                </p>
            </div>
        </section>

        <!-- Application Scenarios -->
        <section class="mb-16">
            <div class="flex items-center mb-6">
                <div class="h-1 bg-indigo-500 w-12 rounded-full"></div>
                <span class="ml-4 text-indigo-600 font-medium">应用场景</span>
            </div>
            <h2 class="text-3xl font-bold mb-6">AOP横切技术典型应用</h2>
            
            <div class="grid md:grid-cols-3 gap-6 mb-8">
                <div class="bg-white p-6 rounded-xl shadow-sm border border-gray-100">
                    <div class="text-green-500 mb-3">
                        <i class="fas fa-clipboard-check text-2xl"></i>
                    </div>
                    <h3 class="text-lg font-semibold mb-2">参数校验</h3>
                    <p class="text-gray-600">自动验证参数合法性，拦截非法输入</p>
                </div>
                <div class="bg-white p-6 rounded-xl shadow-sm border border-gray-100">
                    <div class="text-blue-500 mb-3">
                        <i class="fas fa-scroll text-2xl"></i>
                    </div>
                    <h3 class="text-lg font-semibold mb-2">日志记录</h3>
                    <p class="text-gray-600">自动记录方法调用和参数信息</p>
                </div>
                <div class="bg-white p-6 rounded-xl shadow-sm border border-gray-100">
                    <div class="text-red-500 mb-3">
                        <i class="fas fa-lock text-2xl"></i>
                    </div>
                    <h3 class="text-lg font-semibold mb-2">权限控制</h3>
                    <p class="text-gray-600">拦截未授权访问，实现细粒度权限管理</p>
                </div>
                <div class="bg-white p-6 rounded-xl shadow-sm border border-gray-100">
                    <div class="text-purple-500 mb-3">
                        <i class="fas fa-stopwatch text-2xl"></i>
                    </div>
                    <h3 class="text-lg font-semibold mb-2">性能监控</h3>
                    <p class="text-gray-600">记录方法执行时间，分析性能瓶颈</p>
                </div>
                <div class="bg-white p-6 rounded-xl shadow-sm border border-gray-100">
                    <div class="text-yellow-500 mb-3">
                        <i class="fas fa-exchange-alt text-2xl"></i>
                    </div>
                    <h3 class="text-lg font-semibold mb-2">数据转换</h3>
                    <p class="text-gray-600">统一格式化或转换输入输出数据</p>
                </div>
                <div class="bg-white p-6 rounded-xl shadow-sm border border-gray-100">
                    <div class="text-pink-500 mb-3">
                        <i class="fas fa-exclamation-triangle text-2xl"></i>
                    </div>
                    <h3 class="text-lg font-semibold mb-2">异常处理</h3>
                    <p class="text-gray-600">统一捕获和处理特定异常</p>
                </div>
            </div>
        </section>

        <!-- Best Practices -->
        <section class="mb-16">
            <div class="flex items-center mb-6">
                <div class="h-1 bg-indigo-500 w-12 rounded-full"></div>
                <span class="ml-4 text-indigo-600 font-medium">最佳实践</span>
            </div>
            <h2 class="text-3xl font-bold mb-6">AOP实现横切的最佳实践</h2>
            
            <div class="prose max-w-none text-gray-700 mb-8">
                <ol>
                    <li class="mb-4">
                        <span class="font-semibold">明确切面职责</span> - 每个切面应该只关注一个特定的横切关注点，保持职责单一
                    </li>
                    <li class="mb-4">
                        <span class="font-semibold">合理设计切入点</span> - 使用精确的切入点表达式，避免拦截不需要处理的方法
                    </li>
                    <li class="mb-4">
                        <span class="font-semibold">优先选择自定义注解</span> - 对于需要精准控制的场景，使用自定义注解标记处理目标
                    </li>
                    <li class="mb-4">
                        <span class="font-semibold">注意执行顺序</span> - 使用<code>@Order</code>注解管理多个切面的执行顺序
                    </li>
                    <li class="mb-4">
                        <span class="font-semibold">性能考量</span> - 避免在切面中执行耗时操作，特别是高频调用的方法
                    </li>
                    <li>
                        <span class="font-semibold">异常处理</span> - 在环绕通知中妥善处理异常，避免吞没原始异常
                    </li>
                </ol>
            </div>
        </section>
    </main>

    <!-- Footer -->
    <footer class="bg-gray-900 text-gray-300 py-12">
        <div class="container mx-auto max-w-5xl px-4 md:px-0">
            <div class="flex flex-col md:flex-row justify-between items-center">
                <div class="mb-4 md:mb-0">
                    <h3 class="text-xl font-semibold text-white mb-2">技术小馆</h3>
                    <p class="text-gray-400">探索技术之美，分享编程之道</p>
                </div>
                <div>
                    <a href="http://www.yuque.com/jtostring" class="text-gray-300 hover:text-white transition duration-300 hover-underline-animation">
                        <i class="fas fa-external-link-alt mr-2"></i>www.yuque.com/jtostring
                    </a>
                </div>
            </div>
            <div class="border-t border-gray-800 mt-8 pt-8 text-sm text-gray-500 text-center">
                &copy; 2023 技术小馆. All rights reserved.
            </div>
        </div>
    </footer>

    <script src="https://cdn.jsdelivr.net/npm/mermaid@latest/dist/mermaid.min.js"></script>
    <script>
        mermaid.initialize({
            startOnLoad: true,
            theme: 'default',
            flowchart: {
                useMaxWidth: true,
                htmlLabels: true,
                curve: 'basis'
            }
        });
        
        // Smooth scrolling for anchor links
        document.querySelectorAll('a[href^="#"]').forEach(anchor => {
            anchor.addEventListener('click', function (e) {
                e.preventDefault();
                document.querySelector(this.getAttribute('href')).scrollIntoView({
                    behavior: 'smooth'
                });
            });
        });
    </script>
</body>
</html>
```